﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//指针变量的大小和其类型无关，在同一环境下，大小都一样，为什么还要分类呢？
//指针类型的意义
//1，指针的解引用时有多大的访问权限（一次能操作多少个字节）
//如：int *p=0;一次将四个字节都变为0，char*p=0;一次只能改变（访问）一个字节
//2，指针的加数减数，是跳过多少个字节：（int：4，char：1）
//3，指针加减指针：计算元素个数
// 
//野指针（初始化NULL，已释放，越界。。。）：避免

//assert断言（满足则运行）：
// 用于确保程序运行时符合指定条件，不符合时报错，终止运行
// 报错时甚至可以报出错误文件下的行数
// 头文件：#include<assert.h>才能使用assert(p != NULL)；
/*
//#define NDEBUG   //关闭assert
#include<assert.h>
int main()
{
	int a = 10;
	int* p = &a;
	//...
	//...
	//运行时可能在后面被变为空指针了
	p = NULL;
	//...
	//...
	//此时还想使用p这个指针变量
	//需要用断言来判断它是否已经变为空指针不能使用
	//if (p != NULL)//检测指针的有效性：指向了一块有效空间
	//{
		//...
	//}
	assert(p != NULL);//因为p已经是空指针了，所以”p不是空指针“这个条件为假
	//报错
	return 0;
}
*/
//在已经确定程序没有任何问题bug时，不想再继续使用assert，就在assert的头文件上一行
// 关闭assert：在头文件上一行加上   #define NDEBUG    (不找bug)
//！！！release版本中：assert会被自动屏蔽，debug版本利于程序员调试 找bug

// 指针的使用 和 传址调用
//指针的使用：举例：求字符串长度
/*
#include<string.h>
#include<assert.h>
//自创一个与strlen作用相同的函数
size_t my_strlen(const char* str)//放入的参数是指针类型，用来接收字符串的地址
//不允许通过修改*str来修改str指向的内容
//意思是不能通过指针变量* p来修改p指向的空间内容
// 

{
	size_t count = 0;

	assert(str != NULL);
	//断言:条件：接收的地址不能为空地址，必须是有效的地址
	while (*str !='\0')//遍历每一个元素的地址，遇到'\0'停止，不算'\0'
		//*str：解引用
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	//字符串内是包含'\0'的，所以strlen 是统计'\0'前面的字符个数
	size_t len=my_strlen(arr);//arr是数组名：代表的是第一个（首）元素的地址
	//实际上，strlen 函数返回的是size_t类型的值//size_t==unsigned int
	//最好把int改成size_t
	printf("%zd\n", len);
	return 0;
}
*/


// 函数的调用分为 ：传址调用-----传值调用
//1，传值调用：传的是变量本身的值（没有指针）
// .用在只需要：实现主函数中值的计算
// 例：写一个函数交换两个数的值：传值调用❌ 传址调用 ✔
//传值后函数内会开辟新的地址来存放之前的值
//   形参只是实参的一份临时拷贝，有自己独立的空间
//   修改传值调用的临时变量（形参）时，实参不受影响
//2，传址调用：传递的是地址(涉及指针运算)
// .用于需要修改主函数的值



// 深入理解指针（2）---数组的访问
// .数组名的理解
// 打印&arr[0]  和 打印arr 的结果都是打印数组的首元素的地址
// ！数组名=起始元素的地址
// 但是有两个例外：1， sizeof（数组名）：sizeof(arr)：表示计算整个数组的大小（单位：字节）
//               2，取地址数组名：&arr：表示取出整个数组的地址
/*
int main()
{
	int arr[10] = { 0 };

	printf("%d\n", sizeof(arr));

	//取首元素的地址
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr[0]+1);//+4个字节

	printf("%p\n", arr);
	printf("%p\n", arr+1);//+4个字节

	//取整个元素的地址
	printf("%p\n", &arr);
	printf("%p\n", &arr+1);//+0x28
	//加了x86环境下，十六进制的26=40，加了40个字节
	

	//取地址所有元素的地址，但是地址和上面取出的首元素地址一样，原因：
	//整个数组的起始地址，和首元素的起始地址应该都是第一个元素的地址
	return 0;
}
*/

//用指针访问数组
// ！！！访问数组元素时都是通过地址来访问的
// 
// 依据：
// 1，因为数组在内存中就是连续存放的
// 2，数组名就是起始元素的地址
// 
// 
// 先定义指针变量
// int* p = arr;//p为数组首元素地址
// //p==arr
// for(i=0;i<sz;i++)
// {
// 将scanf("%d",&arr[i]);换为
//   scanf("%d",p+i);
// //           arr+i
// //这里不用加&（取地址符号）因为p已经是地址了
// }
// //打印内存中的数据
// for(i=0;i<sz;i++)
// {
//   printf("%d",*(p+i));//*解引用，取出地址中对应的数据
// //            *(arr+i)
// //             arr[i]
// 
// //所以：  p[i]=*(p+i)
// //实际上，访问下标为n的元素时，每次都是在首元素的地址上偏移，
// 得到下标n的元素的地址，再访问
// 
//          *(arr+i）== arr[i]
// 交换位置：*(i+arr）== i[arr]
// }



// 一维数组传参的本质（数组转递给函数）使用指针
// 
//void test(int arr[])
// //传过来的是首元素的地址，传不了整个数组的地址
// 
//如果要接收整个数组的地址，应该用指针来接收
// 
//int* arr
//{
	//int sz = sizeof(arr) / sizeof(arr[0]);
	//       首元素的大小=4/第一个数组的大小=4  ==1
	// //printf("%d\n", sz);//得到的不是元素个数
//}
/*
//void print(int arr[])
void print(int* arr,int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		//printf("%d ", arr[i]);
		printf("%d ", *(arr + i));
		//arr[i]==*(arr+i)
		//相当于还是用起始地址加数（指针）来访问i元素的值
	}
}
int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int sz= sizeof(arr) / sizeof(arr[0]);
	//求总元素个数一定要在传参之前，在主函数内求

	print(arr,sz);//arr：首元素地址
	//数组传参的时候，传递的不是数组
	
	return 0;
}
*/


//写一个函数，对一个整型数组进行排序
void BBB(int arr[], int sz)
{
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j <sz-1-i ; j++)
		{
			if (arr[j] > arr[j + 1])//如果不满足升序
			{
				//则交换
				int tep = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tep;
			}

		}
	}

}



int main()
{
	int arr[] = {9,8,7,6,5,4,3,2,1,0};
	int sz = sizeof(arr) / sizeof(arr[0]);
	//把数组排序为升序
	BBB(arr,sz);
	//使用冒泡排序：相邻两数作比较，如果不满足顺序，则交换位置
	//一趟只能排出一个正确的值
	//一共要排序n-1次
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}


//  
// 
// 
// 
// 
// 
// 
// 
// .
// .
// .
// 
//
// 
// 
// 
// 
// 
//

// 
// 
// 
// 
// 
//


















































































































